#include <iostream>
#include <string>
#include <functional>
#include <sys/types.h> /* See NOTES */
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <cstring>
#include <pthread.h>
#include <sys/types.h>
#include <sys/wait.h>

#include "InetAddr.hpp"
#include "Log.hpp"
#include "ThreadPool.hpp"

enum{
    SOCK_ERROR = 1,
    BIND_ERRROR,
    LISTEN_ERROR,
    USAGE_ERROR
};

const static uint16_t defaultsockfd = -1;
const static int backlog = 16;
class TcpServer;
using task_t = std::function<void()>;

class ThreadData{
public:
    ThreadData(int sockfd, InetAddr client, TcpServer* s):_sockfd(sockfd),_client(client), self(s){}
    int _sockfd;
    InetAddr _client;
    TcpServer* self;
};

class TcpServer{
public:
    TcpServer(uint16_t port = defaultsockfd):_port(port), _isrunning(false){}
    void InitServer(){
        _listensockfd = ::socket(AF_INET, SOCK_STREAM, 0);
        if(_listensockfd < 0){
            LOG(FATAL, "sockfd error");
            exit(SOCK_ERROR);
        }
        LOG(INFO,"socket created success : %d\n", _listensockfd);

        //2.0 bind
        struct sockaddr_in local;
        memset(&local, 0, sizeof(local));
        local.sin_family = AF_INET;
        local.sin_port = htons(_port);
        local.sin_addr.s_addr = INADDR_ANY;

        int fd = bind(_listensockfd, (struct sockaddr*)&local, sizeof(local));
        if(fd < 0){
            LOG(FATAL,"bind failed\n");
            exit(BIND_ERRROR);
        }
        LOG(INFO,"bind success!\n");

        //3.0监听
        fd = listen(_listensockfd, backlog);
        if(fd < 0){
            LOG(FATAL, "listen fail\n");
            exit(LISTEN_ERROR);
        }
        LOG(INFO,"listen success!\n");
    }

    void Service(int sockfd, InetAddr client){
        LOG(DEBUG, "get a new link, info %s:%d, fd : %d\n", client.Getip().c_str(), client.Getport(), sockfd);
        std::string clientaddr = "[" + client.Getip() + ":" + std::to_string(client.Getport()) + "]# ";
        while(true){
            char inbuffer[1024];
            ssize_t n = read(sockfd, inbuffer, sizeof(inbuffer) - 1);
            if(n > 0){
                inbuffer[n] = 0;
                std::cout << clientaddr << inbuffer << std::endl;
                std::string echo_string = "[server echo: ]";
                echo_string += inbuffer;
                n = write(sockfd, echo_string.c_str(), echo_string.size());
            } else if (n == 0) {
                LOG(INFO, "%s quiet\n", clientaddr.c_str());
                break;
            } else {
                LOG(ERROR, "read error\n");
                break;
            }
        }
        close(sockfd);
    }

    static void* HandlerSock(void* args){
        pthread_detach(pthread_self());
        ThreadData *td = static_cast<ThreadData *>(args);
        td->self->Service(td->_sockfd, td->_client);
        delete td;
        return nullptr;
    }

    void Loop(){
        _isrunning = true;
        struct sockaddr_in peer;
        socklen_t len = sizeof(peer);
        while(_isrunning){
            int sockfd = accept(_listensockfd, (struct sockaddr*)&peer, &len);
            if(sockfd < 0){
                LOG(WARNING, "accept fail\n");
                continue;;
            }
            //多进程版本
            // pid_t id = fork();
            // if(id == 0){
            //     ::close(_listensockfd);
            //     if(fork() > 0) exit(0);
            //     InetAddr client(peer);
            //     Service(sockfd, client);
            //     exit(0);
            // }
            // ::close(sockfd);
            // waitpid(id, nullptr, 0);

            //多线程版本
            pthread_t t;
            ThreadData *td = new ThreadData(sockfd, InetAddr(peer), this);
            pthread_create(&t, nullptr, HandlerSock, td); //将线程分离
        }
    }
    ~TcpServer(){
        if(_listensockfd > defaultsockfd) close(_listensockfd);
    }
private:
    uint16_t _port;
    int _listensockfd;
    bool _isrunning;
};